package com.netty.server;

import com.netty.handler.WebSocketNettyHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.logging.LoggingHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

/**
 * @author renyitong
 * @version 1.0.0
 * @createTime 2023年08月16日
 * @Description netty服务端
 * 实现DisposableBean 在容器销毁前会调用destroy 方法进行线程组的关闭
 */
@Component
@Slf4j
public class NettyWebSocketServer implements DisposableBean {

    /**
     * 自定义入站规则
     */
    @Autowired
    private WebSocketNettyHandler webSocketNettyHandler;

    /**
     * 通道初始化对象
     */
    @Autowired
    private NettyWebSocketChannelInit webSocketChannelInit;

    /**
     * boosGroup线程组
     */
    private EventLoopGroup bossGroup;

    /**
     * workGroup线程组
     */
    private EventLoopGroup workGroup;


    /**
     * 自定义启动方法
     *
     * @param port
     */
    public void start(int port) throws InterruptedException {
        // 设置boos线程组
        bossGroup = new NioEventLoopGroup(1);
        // 设置work线程组
        workGroup = new NioEventLoopGroup();
        // 创建启动助手
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workGroup)
                .channel(NioServerSocketChannel.class)
                .handler(new LoggingHandler())
                .childHandler(webSocketChannelInit);

        // 绑定ip和端口启动服务端
        ChannelFuture channelFuture = null;
        try {
            // 同步等待直到服务器成功绑定到指定的端口为止
            channelFuture = bootstrap.bind(port).sync();
        } catch (InterruptedException e) {
            e.printStackTrace();
            this.close();
        }

        log.info("netty服务器启动成功" + "--端口: {}", port);
        // 对关闭通道进行监听
        channelFuture.channel().closeFuture().sync();
    }


    /**
     * 容器销毁前关闭线程组
     *
     * @throws Exception
     */
    @Override
    public void destroy() throws Exception {
        this.close();
    }

    /**
     * 关闭方法
     */
    public void close() throws InterruptedException {
        if (bossGroup != null) {
            bossGroup.shutdownGracefully().sync();
        }
        if (workGroup != null) {
            workGroup.shutdownGracefully().sync();
        }
    }

}
